package com.ricky.base.bean;

import com.jcraft.jsch.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author Ricky
 * @date 2020/11/30
 */
@Data
@Slf4j
public class SshClient implements AutoCloseable {
    private String host;
    private String username;
    private String password;
    private int port;

    private Session session;

    public SshClient(String host, String username, String password) throws JSchException {
        this(host, username, password, 22);
    }

    public SshClient(String host, String username, String password, int port) throws JSchException {
        this.host = host;
        this.username = username;
        this.password = password;
        this.port = port;

        connectServer();
    }

    private void connectServer() throws JSchException {
        JSch jsch = new JSch();
        session = jsch.getSession(username, host, port);
        // 设置密码
        session.setPassword(password);
        // 需要实现Jsch包中的UserInfo,UIKeyboardInteractive接口，
        // 用以保存用户信息，以及进行键盘交互式认证并执行命令。
        session.setUserInfo(new MyUserInfo());
        Properties config = new Properties();
        //在代码里需要跳过检测。否则会报错找不到主机
        config.put("StrictHostKeyChecking", "no");
        // 为Session对象设置properties
        session.setConfig(config);
        int timeout = 30000;
        // 设置timeout时间
        session.setTimeout(timeout);
        // 通过Session建立与远程服务器的连接回话
        try {
            session.connect();
        } catch (Exception e) {
            String message = e.getMessage();
            if ("java.net.ConnectException: Connection refused: connect".equals(message)) {
                throw new RuntimeException("拒绝连接-->请检查主机是否开机或填写错误！", e);
            } else if ("java.net.ConnectException: Connection timed out: connect".equals(message)) {
                throw new RuntimeException("连接超时-->请检查主机是否开机或填写错误！", e);
            } else if (message.startsWith("java.net.UnknownHostException:")) {
                throw new RuntimeException("主机【" + host + "】填写错误，请检查！", e);
            } else if ("Auth cancel".equals(message)) {
                throw new RuntimeException("用户名或密码错误，请检查！", e);
            }
            e.printStackTrace();
        }
        log.info("连接服务器【{}:{}】成功", host, port);
    }

    public void exec(String command) throws JSchException, IOException {
        ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
        //添加传入进来的shell命令
        channelExec.setCommand(command);
        channelExec.setInputStream(null);
        //通道连接错误信息提示
        channelExec.setErrStream(System.err);
        channelExec.connect();
        log.info("开始执行命令：{}", command);
        try (BufferedReader in = new BufferedReader(new InputStreamReader(channelExec.getInputStream()))) {
            String msg;
            log.info("开始读取数据!");
            while ((msg = in.readLine()) != null) {
                log.info("命令返回信息：{}", msg);
            }
        }
        channelExec.disconnect();
        log.info("命令执行完成!");
    }

    public List<String> execToList(String command) throws JSchException, IOException {
        ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
        //添加传入进来的shell命令
        channelExec.setCommand(command);
        channelExec.setInputStream(null);
        //通道连接错误信息提示
        channelExec.setErrStream(System.err);
        channelExec.connect();
        log.info("开始执行命令!");
        List<String> res = new ArrayList<>();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(channelExec.getInputStream()))) {
            String msg;
            log.info("开始读取数据：{}", command);
            while ((msg = in.readLine()) != null) {
                res.add(msg);
            }
        }
        channelExec.disconnect();
        log.info("命令执行完成!");
        return res;
    }

    public void downloadFile(String directory, String downloadFile, String saveDir) throws JSchException, FileNotFoundException, SftpException {
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        log.info("开始下载文件!");
        channelSftp.cd(directory);
        File file = new File(saveDir + File.separator + downloadFile);
        channelSftp.get(downloadFile, new FileOutputStream(file));
        log.info("文件下载成功!");
        channelSftp.disconnect();
        log.info("关闭sftp连接!");
    }

    public void uploadDile(String directory, File file) throws JSchException, SftpException, IOException {
        uploadDile(directory, new FileInputStream(file), file.getName());
    }

    public void uploadDile(String directory, File file, String fileName) throws JSchException, SftpException, IOException {
        uploadDile(directory, new FileInputStream(file), fileName);
    }

    public void uploadDile(String directory, MultipartFile file) throws JSchException, IOException, SftpException {
        uploadDile(directory, file.getInputStream(), file.getOriginalFilename());
    }

    public void uploadDile(String directory, MultipartFile file, String fileName) throws JSchException, IOException, SftpException {
        uploadDile(directory, file.getInputStream(), fileName);
    }

    public void uploadDile(String directory, InputStream src, String fileName) throws JSchException, IOException, SftpException {
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();
        log.info("开始上传文件!");
        channelSftp.cd(directory);
        channelSftp.put(src, fileName);
        log.info("文件上传成功!");
        channelSftp.disconnect();
        log.info("关闭sftp连接!");
    }

    @Override
    public void close() {
        session.disconnect();
    }

    public static void main(String[] args) throws JSchException, IOException, SftpException {
        SshClient sshClient = new SshClient("192.168.7.126", "root", "root");
        //        sshClient.exec("ls /home/swx/test/");
        //        File upFile = new File("E:\\Users\\Ricky\\Desktop\\新建文本文档.txt");
        //        sshClient.uploadDile("/home/swx/test/", upFile);
        sshClient.downloadFile("/home/swx/test/", "新建文本文档.txt", "E:\\Users\\Ricky\\Desktop\\Case");
        sshClient.close();
    }
}
